<?php

declare(strict_types=1);

namespace App\Middleware;

use Hyperf\Context\Context;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Snowflake\IdGeneratorInterface;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class RequestMiddleware implements MiddlewareInterface
{
    public function __construct(
        protected ContainerInterface $container
    )
    {
    }

    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Throwable
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $generator = $this->container->get(IdGeneratorInterface::class);
        $requestId = $generator->generate();
        Context::set('request_id', $requestId);
        $startTime = microtime(true);
        $requestInterface = $this->container->get(RequestInterface::class);
        logs('-----------------------------------------------------', 'params');
        logs('headers', 'params', $request->getHeaders());
        logs('body', 'params', $requestInterface->all());
        $uri = "{$request->getUri()->getScheme()}://{$request->getUri()->getHost()}".($request->getUri()->getPort()?":{$request->getUri()->getPort()}":'')."{$request->getUri()->getPath()}".($request->getUri()->getQuery()?'?':'')."{$request->getUri()->getQuery()}";
        logs('uri', 'params', [$request->getMethod()=>$uri]);

        try {
            $next = $handler->handle($request);
        } catch (\Throwable $throwable) {
            throw $throwable;
        } finally  {
            $runtime    = round(microtime(true) - $startTime, 5);
            logs('runtime', 'params', ["运行时间：{$runtime}s"]);
        }
        return $next;
    }
}
